package com.linkgie.galaxyframework.kvstorage.spi;

import java.io.Closeable;
import java.net.URI;

/**
 * 键值存储仓库的核心接口；
 * 
 * @author spring
 *
 */
public interface KVDatabase extends Closeable, KVDataview {

	/**
	 * 数据库的Id；
	 * 
	 * @return
	 */
	String getId();

	/**
	 * 创建数据库的 URI ；
	 * 
	 * @return
	 */
	URI getURI();

	/**
	 * 是否可用；
	 * <p>
	 * 
	 * 实现者应遵循以下规则：<br>
	 * 1. 处于可用状态时（即 {@link #isAlived()} 返回 true），应保证可正常调用
	 * {@link #get(byte[])}、{@link #setValue(byte[])} 方法进行键值读写操作；<br>
	 * 
	 * 2. 如果状态为非可用状态时（即 {@link #isAlived()} 返回 false），则调用
	 * {@link #get(byte[])}、{@link #setValue(byte[])} 方法读写时引发
	 * {@link KVDatabaseStateException} 异常；<br>
	 * 
	 * 3. 初始时可用状态可以由实现者定义，即通过 {@link KVStorageProvider#createRepository(URI)}
	 * 方法返回 {@link KVDatabase} 实例时，该实例的 {@link #isAlived()} 可以返回 true 或者
	 * false；
	 * 
	 * 4. 如果已经处于可用状态，则调用 {@link #open()} 方法不会产生额外影响；
	 * 
	 * 5. 如果处于非可用状态，则调用 {@link #open()} 方法正常返回之后变为可用状态；
	 * 
	 * 6. 当已经处于可用状态时，直到显式地调用 {@link #close()} 方法关闭之前, 都一直处于可用状态；
	 * 
	 * 7. 实现者可以自行决定在初始之后直到关闭之前的整个生命周期中是否动态管理仓库的可用状态，但状态呈现应遵循以上规则；
	 * 例如，在长期没有调用时自动关闭仓库以释放资源，但应该确保以内部状态进行管理，努力确保在关闭之前无论何时调用读写操作都能成功；
	 * 
	 * @return
	 */
	boolean isAlived();

	/**
	 * 打开数据库使其处于可用状态（{@link #isAlived()} 返回 true）；
	 * <p>
	 * 
	 * 当此 {@link KVDatabase} 实例表示的数据库被初始化创建时，键值存储管理器遵循以下执行规则： <br>
	 * 1. 如果创建实例之后处于可用状态（{@link #isAlived()} 返回 true），则键值存储管理器不会主动调用
	 * {@link #open()} 方法； <br>
	 * 2. 如果创建实例之后处于非可用状态（{@link #isAlived()} 返回 false），则键值存储管理器将会调用一次
	 * {@link #open()} 方法使其转为可用状态； 但调用的时机（立即调用/延迟调用）由键值存储管理器的策略决定，实现者不应依赖于其中某种假设；
	 * <br>
	 * 
	 * 实现者应遵循以下原则：<br>
	 * 1. 如果操作前已经处于可用状态，则调用此方法不产生任何影响，并且正常返回； <br>
	 * 
	 * 2. 如果操作前处于非可用状态，则调用此方法正常返回之后立即变为可用状态；<br>
	 * 
	 * 3. 如果操作前处于非可用状态，当调用此方法时无法使其转为可用状态，无论出于何种原因，都应抛出
	 * {@link KVDatabaseStateException} 并提供具体原因描述；<br>
	 * 
	 * 4. 实现者可以决定是否允许在关闭之后重新打开，但必须遵循以上约定；
	 * 
	 */
	void open() throws KVDatabaseStateException;

	/**
	 * 关闭键值仓库释放相关资源；
	 * <p>
	 * 
	 * 实现者应遵循以下规则：<br>
	 * 1. 调用方法之后，键值存储仓库处于非可用状态（{@link #isAlived()} 返回 false)；<br>
	 * 2. 确保方法总是能够正常返回，无论关闭处理的过程发生何种异常，都应在内部完成处理，而确保当前实例的生命周期状态必然到达终点；
	 */
	@Override
	void close();
}
